Skip to content

refactor(asusctl): modularize CLI handlers into dedicated modules and fix service status guards - #238

Open
scardracs wants to merge 8 commits into
OpenGamingCollective:mainfrom
scardracs:refactor/asusctl-cli
Open

refactor(asusctl): modularize CLI handlers into dedicated modules and fix service status guards#238
scardracs wants to merge 8 commits into
OpenGamingCollective:mainfrom
scardracs:refactor/asusctl-cli

Conversation

@scardracs

@scardracs scardracs commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Description

This PR modularizes the monolithic asusctl CLI entry point into focused, single-responsibility modules, consolidates D-Bus helper functions into rog-dbus and improves daemon/CLI resilience and performance.

Key Changes

  • CLI Modularization (asusctl):

    • Extracted CLI subcommand logic from asusctl/src/main.rs (removing ~970 lines of monolithic code) into dedicated handler modules:
      • platform_cli.rs: Platform settings (fan profiles, CPU governor/power limits, charge thresholds, Panel OD, Armoury attributes).
      • anime_cli.rs: AniMe Matrix display configuration and image/gif rendering handlers.
      • fan_curve_cli.rs: Custom fan curve editing and upload subcommands.
      • scsi_cli.rs: External SCSI LED lighting subcommands.
      • slash_cli.rs: Slash lighting bar control subcommands.
      • xgm_led_cli.rs: XG Mobile eGPU LED status and toggle subcommands.
  • D-Bus Helpers Consolidation (rog-dbus):

    • Consolidated duplicate find_iface_blocking and find_iface_async proxy lookup functions across asusctl and rog-control-center into rog-dbus.
  • Structured Logging & Code Quality:

    • Converted legacy println! / eprintln! calls across asusctl CLI modules and asusd daemon (asusd/src/daemon.rs) to structured log macros (info!, warn!, error!).
    • Moved logger initialization in asusd to the top of main() ensuring early startup logs are captured.
  • Service Guards, Resilience & Performance Optimizations:

    • Implemented daemon availability checks (check_service) before dispatching D-Bus calls, providing friendly diagnostic output when asusd is inactive.
    • Hoisted argument validation and D-Bus proxy instantiations out of high-frequency iteration loops.
    • Fixed multi-device handling in the Aura power loop.
    • Resolved scsi --list execution requirement so it can run independently of daemon status.
    • Fixed AniMe Matrix override-type handling.

Verification Passed

  • cargo check --all-targets
  • cargo test --all
  • cargo clippy --workspace --all-targets --all-features -- -D warnings
  • cargo cranky
  • cargo fmt --all -- --check

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Expanded platform controls for battery charging, brightness, backlight, keyboard modes, lighting, profiles, firmware attributes, and device information.
    • Added anime animation controls, fan-curve management, SCSI Aura configuration, and GPU status reporting.
    • Added support for viewing and configuring additional device lighting and control options.
  • Improvements

    • Standardized command output and diagnostics through structured logging, with clearer warnings and errors.
    • Improved command validation and handling of unsupported or incomplete requests.

Walkthrough

The PR modularizes asusctl command handling, adds anime, fan-curve, platform, and SCSI handlers, introduces blocking D-Bus discovery, and replaces direct console output with structured logging across related components.

Changes

asusctl command handlers

Layer / File(s) Summary
Anime command handler
asusctl/src/anime_cli.rs
Replaces the anime option with AnimeActions. Adds D-Bus-backed display updates, image and GIF playback, builtin animations, loop handling, brightness validation, and tests.
Fan-curve and SCSI handlers
asusctl/src/fan_curve_cli.rs, asusctl/src/scsi_cli.rs
Adds validation and D-Bus operations for fan curves and SCSI Aura devices.
Platform operation handlers
asusctl/src/platform_cli.rs
Adds handlers for platform information, battery, backlight, brightness, LED modes and power, profiles, and Armoury attributes.
Command dispatch and CLI output
asusctl/src/main.rs, asusctl/src/slash_cli.rs, asusctl/src/xgm_led_cli.rs
Delegates commands to dedicated modules, shares the D-Bus connection, and routes command output and diagnostics through logging.

D-Bus and structured logging support

Layer / File(s) Summary
Blocking D-Bus discovery
rog-dbus/*, rog-control-center/src/zbus_proxies.rs
Adds synchronous interface discovery and a GPU status proxy.
Control-center diagnostics
rog-control-center/src/lib.rs, rog-control-center/src/main.rs
Routes version information, retrieval failures, and version mismatches through logging.
Runtime logging migration
asus-shutdown/src/main.rs, asusd/src/daemon.rs, rog-anime/src/data.rs, rog-aura/src/keyboard/layouts.rs, simulators/src/simulator.rs
Replaces direct console output with informational or warning logs.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested labels: asusctl, rog-aura, rog-anime, rog-platform, rog-scsi, rog-slash, rog-control-center, asusd, fix

Suggested reviewers: neroreflex, ghoul4500

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main refactoring and service-guard changes in the pull request.
Description check ✅ Passed The description explains the main changes and lists verification results, but it omits the issue reference and hardware and environment details.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot added asusctl CLI Tool fix Fix a bug or an issue rog-anime AniMe Matrix Display rog-control-center ROG Control Center GUI rog-platform GPU Switching / Armoury / WMI rog-profiles Power Profiles / Fan Curves rog-scsi Drive / SCSI LED rog-slash Slash LED Bar labels Jul 29, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
asusctl/src/main.rs (1)

102-108: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer conn: &Connection over suppressing the lint.

do_parsed only ever passes &conn to handlers, so taking the borrow removes the need for #[allow(clippy::needless_pass_by_value)].

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@asusctl/src/main.rs` around lines 102 - 108, Update do_parsed to accept conn
as &Connection instead of Connection, remove the
#[allow(clippy::needless_pass_by_value)] attribute, and preserve the existing
handler calls by passing the borrowed connection through.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@asusctl/src/anime_cli.rs`:
- Around line 205-291: The argument checks in the anime and platform handlers
run inside per-device loops, causing repeated warnings and partial updates
before returning. In asusctl/src/anime_cli.rs lines 205-291, hoist the image,
pixel-image, gif, pixel-gif path.is_empty() checks and SetBuiltins
builtins.set.is_none() check before the for proxy in animes loop, returning
before proxy work; in asusctl/src/platform_cli.rs lines 344-348, move the
power.command let Some(...) else validation before the for aura in aura loop and
remove the empty “Commands available” print.
- Around line 170-177: Update the anime type selection around get_anime_type so
cmd.override_type is applied unconditionally whenever provided, regardless of
whether detection returns Unsupported. Retain the warning only for an
Unsupported detected type when no override is supplied.

In `@asusctl/src/platform_cli.rs`:
- Line 72: Move the rog_dbus::find_iface_blocking import from its current
location into the file’s existing top-level import block, without changing its
usage.
- Around line 289-300: Update the loop over AuraProxyBlocking devices to track
whether any eligible device was handled instead of returning immediately from
the first match. Call handle_led_power_1_do_1866 for every old or TUF laptop,
then emit the existing warning only after iteration when no matching device was
found, preserving the function’s successful return behavior.
- Around line 512-561: The handle_armoury_command function repeats the armoury
interface lookup in each subcommand arm. Resolve attrs once before matching on
cmd.command, then reuse it in List, Get, and Set; optionally extract the shared
Get/Set attribute search while preserving their distinct read versus mutation
behavior.
- Around line 482-496: Update the possible-values output block around the `p.0`
checks to always emit a terminating newline after printing the closing `]`,
before the `has_default` branch prints `default:` or the blank line. Preserve
the existing comma and closing-bracket formatting.
- Around line 118-135: Construct a single PlatformProxyBlocking instance before
the match on cmd.command, then reuse that proxy in the Limit, OneShot, and Info
arms. Remove the repeated PlatformProxyBlocking::new(conn)? calls while
preserving each arm’s existing operations and error propagation.

In `@asusctl/src/scsi_cli.rs`:
- Around line 46-47: Update the scsi command flow around find_iface_blocking and
the cmd.list handling so --list is processed before D-Bus interface discovery
and succeeds without asusd or the SCSI interface. Only call find_iface_blocking
when device options are supplied, while preserving existing behavior for
device-specific operations.

In `@asusctl/src/slash_cli.rs`:
- Around line 82-83: Update the no-argument branch in the slash command handler
to return immediately after emitting the missing-argument warning. Ensure the
early return occurs before opening the system connection or constructing the
Slash proxy, while preserving the existing usage message.

---

Outside diff comments:
In `@asusctl/src/main.rs`:
- Around line 102-108: Update do_parsed to accept conn as &Connection instead of
Connection, remove the #[allow(clippy::needless_pass_by_value)] attribute, and
preserve the existing handler calls by passing the borrowed connection through.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 50e31e4d-5cc3-4278-bb3c-8ae52471e7fa

📥 Commits

Reviewing files that changed from the base of the PR and between 90da2df and 3617134.

📒 Files selected for processing (9)
  • asusctl/src/anime_cli.rs
  • asusctl/src/fan_curve_cli.rs
  • asusctl/src/main.rs
  • asusctl/src/platform_cli.rs
  • asusctl/src/scsi_cli.rs
  • asusctl/src/slash_cli.rs
  • rog-control-center/src/main.rs
  • rog-control-center/src/mocking.rs
  • rog-control-center/src/zbus_proxies.rs
📜 Review details
🔇 Additional comments (15)
rog-control-center/src/zbus_proxies.rs (2)

1-5: LGTM!

Also applies to: 71-89


91-91: 🎯 Functional Correctness

No compatibility alias needed. No live Rust callers still reference find_iface; the only remaining occurrence is a commented example.

			> Likely an incorrect or invalid review comment.
rog-control-center/src/mocking.rs (1)

5-6: LGTM!

Also applies to: 98-125, 137-137, 152-154, 165-165, 198-202

rog-control-center/src/main.rs (1)

83-91: LGTM!

asusctl/src/anime_cli.rs (3)

2-5: LGTM!

Also applies to: 35-37


295-325: LGTM!

Also applies to: 327-375


199-203: 🎯 Functional Correctness

Use a zeroed buffer for clear. AnimeDataBuffer::new() starts with 0u8, and the other clear path also sends vec![0u8; ...]; 255 would light the whole panel.

			> Likely an incorrect or invalid review comment.
asusctl/src/fan_curve_cli.rs (1)

2-2: LGTM!

Also applies to: 46-119

asusctl/src/platform_cli.rs (5)

1-19: LGTM!

Also applies to: 21-70


74-112: LGTM!

Also applies to: 140-217


219-276: LGTM!

Also applies to: 306-333, 350-388


390-434: LGTM!


436-481: LGTM!

Also applies to: 500-510

asusctl/src/main.rs (1)

1-19: LGTM!

Also applies to: 95-100, 117-131

asusctl/src/slash_cli.rs (1)

2-2: LGTM!

Also applies to: 142-149

Comment thread asusctl/src/anime_cli.rs Outdated
Comment thread asusctl/src/anime_cli.rs
Comment thread asusctl/src/platform_cli.rs Outdated
Comment thread asusctl/src/platform_cli.rs
Comment thread asusctl/src/platform_cli.rs
Comment thread asusctl/src/platform_cli.rs Outdated
Comment thread asusctl/src/platform_cli.rs Outdated
Comment thread asusctl/src/scsi_cli.rs
Comment thread asusctl/src/slash_cli.rs
@scardracs
scardracs force-pushed the refactor/asusctl-cli branch from 0acfc9e to dbd9a0e Compare August 3, 2026 19:45
@coderabbitai coderabbitai Bot added asusd System Daemon / D-Bus and removed rog-profiles Power Profiles / Fan Curves labels Aug 3, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
rog-control-center/src/zbus_proxies.rs (1)

91-126: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the shared blocking interface helper.

rog_dbus::find_iface_blocking now implements this operation. This local copy already differs in its log level and its no-interface error text.

Re-export the shared helper with find_iface_async. Remove this duplicate implementation.

Proposed change
-pub use rog_dbus::find_iface_async;
-
-pub fn find_iface_blocking<T>(iface_name: &str) -> Result<Vec<T>, Box<dyn std::error::Error>>
-where
-    T: zbus::blocking::proxy::ProxyImpl<'static> + From<zbus::Proxy<'static>>,
-{
-    // local implementation
-}
+pub use rog_dbus::{find_iface_async, find_iface_blocking};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rog-control-center/src/zbus_proxies.rs` around lines 91 - 126, Replace the
local find_iface_blocking implementation with a re-export of
rog_dbus::find_iface_blocking alongside find_iface_async. Remove the duplicate
connection, interface lookup, logging, sorting, proxy construction, and
no-interface error-handling code from this module.
asusctl/src/main.rs (1)

101-107: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Take conn by reference instead of suppressing the lint.

do_parsed never consumes conn; every use at lines 115-126 borrows it. Change the parameter to &Connection and remove the allow attribute.

♻️ Proposed refactor
-#[allow(clippy::needless_pass_by_value)]
 fn do_parsed(
     parsed: &CliStart,
     supported_interfaces: &[String],
     supported_properties: &[Properties],
-    conn: Connection,
+    conn: &Connection,
 ) -> Result<(), Box<dyn std::error::Error>> {

Update the call site at line 83:

if let Err(err) = do_parsed(&parsed, &supported_interfaces, &supported_properties, &conn) {

Then replace &conn with conn in the handler calls at lines 115, 116, 124, and 126.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@asusctl/src/main.rs` around lines 101 - 107, Update do_parsed to accept conn
as &Connection and remove the clippy::needless_pass_by_value suppression. Pass
&conn at its call site, then pass conn directly to each handler invocation
inside do_parsed, preserving the existing behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@asusctl/src/anime_cli.rs`:
- Around line 195-198: Preserve the presence validation in the
AnimeActions::SetBuiltins branch, but use the contained builtins.set boolean
when reaching the proxy.set_builtin_animations apply path. Only invoke the proxy
operation when the value is true; treat Some(false) as a valid no-op rather than
applying the change unconditionally.
- Around line 152-201: Move the per-action validation block keyed by
cmd.command.as_ref() and matching AnimeActions variants before
find_iface_blocking and get_anime_type in handle_anime. Preserve all existing
warnings and early returns for empty image, pixel-image, gif, pixel-gif paths,
and missing SetBuiltins.set, so invalid arguments are rejected before any D-Bus
discovery or anime-type lookup.

In `@asusctl/src/main.rs`:
- Around line 116-129: Update the command dispatch around handle_slash_get,
handle_slash_set, and xgm_led_cli::handle_xgm_led to pass the existing &conn,
and change those handler signatures and their call sites to accept and reuse the
shared Connection instead of opening another system bus connection. Preserve the
current SlashSubCommand behavior and error propagation while applying the same
shared-connection pattern used by fan_curve_cli::handle_fan_curve and
handle_battery.
- Around line 95-98: Update the CLI logging initialization around the existing
filter_level and env_logger target configuration to use an info-level default
filter while still honoring explicit RUST_LOG settings, and keep the logger
output on stdout rather than configuring env_logger::Target::Stderr. Ensure the
info! records in main remain visible as primary command results and continue
supporting pipelines and stdout redirection.

In `@asusctl/src/platform_cli.rs`:
- Around line 546-555: Update the attribute handling around the local name
binding to reuse the result from attr.name() when checking property_type(),
eliminating the second name() D-Bus call. Ensure the value remains available
after the comparison with s.property, using a reference or clone if the
conversion moves it, and preserve the existing FirmwareAttributeType::Ppt
behavior.
- Around line 41-51: Update check_systemd_unit_active to return true only when
systemctl is-active produces the exact active state, trimming the stdout before
comparison. Treat activating, deactivating, unknown, inactive, failed, command
errors, and other outputs as false.
- Around line 464-469: Update the match in the current-value reporting logic to
handle (None, Some(c), None) by logging c as the current value instead of
reporting it unavailable. Preserve the existing formatting for all other
min/c/max combinations.
- Around line 515-521: Remove the #[allow(clippy::manual_is_multiple_of,
clippy::nonminimal_bool)] attribute immediately above handle_armoury_command,
leaving the function signature and implementation unchanged so both Clippy lints
are enforced.
- Around line 309-331: Add a validation in the aura power command before
constructing LaptopAuraPower or calling aura.set_led_power so an empty states
collection is rejected when no --keyboard or --lightbar zone was selected. Emit
a clear warning or error and return an appropriate failure result, while
preserving the existing behavior when at least one zone is selected.
- Around line 289-296: Update the device-type branching around
handle_led_power_1_do_1866 so the warning is emitted when the handler does not
apply, using the same predicate for both warning and handling without evaluating
it twice. Preserve handle_led_power_1_do_1866 and handled = true only for old or
TUF laptops, and ensure the warning describes that supported scope.

In `@asusctl/src/scsi_cli.rs`:
- Around line 56-98: Update the SCSI device-processing closure around
led_mode_data and set_led_mode_data to handle each device’s errors locally, log
the device context, and continue processing remaining devices instead of
propagating failures through ?. Adjust the closure return type and error
handling to match the actual operation signatures. Move the “first 4 colours”
warning out of the scsis loop so it is emitted only once.

In `@asusd/src/daemon.rs`:
- Around line 40-41: Update the two warn! messages in the daemon startup
guidance to correct the spelling of “should” and the grammar in the journalctl
instruction, while preserving the existing service and command references.

In `@rog-control-center/src/lib.rs`:
- Around line 25-33: Ensure the --version path in main remains visible when
RUST_LOG is unset by emitting the version information directly to stdout or
initializing that path with an info-level filter. Update the version-reporting
block containing the rog-gui, asusd, and component crate version messages while
preserving the existing output content.

---

Outside diff comments:
In `@asusctl/src/main.rs`:
- Around line 101-107: Update do_parsed to accept conn as &Connection and remove
the clippy::needless_pass_by_value suppression. Pass &conn at its call site,
then pass conn directly to each handler invocation inside do_parsed, preserving
the existing behavior.

In `@rog-control-center/src/zbus_proxies.rs`:
- Around line 91-126: Replace the local find_iface_blocking implementation with
a re-export of rog_dbus::find_iface_blocking alongside find_iface_async. Remove
the duplicate connection, interface lookup, logging, sorting, proxy
construction, and no-interface error-handling code from this module.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: aa159c36-b7ad-4823-87d8-8bf8211379da

📥 Commits

Reviewing files that changed from the base of the PR and between 3617134 and dbd9a0e.

📒 Files selected for processing (17)
  • asus-shutdown/src/main.rs
  • asusctl/src/anime_cli.rs
  • asusctl/src/fan_curve_cli.rs
  • asusctl/src/main.rs
  • asusctl/src/platform_cli.rs
  • asusctl/src/scsi_cli.rs
  • asusctl/src/slash_cli.rs
  • asusctl/src/xgm_led_cli.rs
  • asusd/src/daemon.rs
  • rog-anime/src/data.rs
  • rog-aura/src/keyboard/layouts.rs
  • rog-control-center/src/lib.rs
  • rog-control-center/src/main.rs
  • rog-control-center/src/zbus_proxies.rs
  • rog-dbus/Cargo.toml
  • rog-dbus/src/lib.rs
  • simulators/src/simulator.rs
📜 Review details
🔇 Additional comments (29)
rog-dbus/Cargo.toml (1)

20-20: LGTM!

rog-dbus/src/lib.rs (1)

76-76: LGTM!

Also applies to: 96-129

rog-control-center/src/zbus_proxies.rs (1)

71-89: LGTM!

rog-control-center/src/main.rs (1)

86-91: LGTM!

asus-shutdown/src/main.rs (1)

155-171: LGTM!

asusd/src/daemon.rs (1)

32-38: LGTM!

Also applies to: 42-42

rog-anime/src/data.rs (1)

7-7: LGTM!

Also applies to: 320-320

rog-aura/src/keyboard/layouts.rs (1)

308-308: LGTM!

Also applies to: 474-474

simulators/src/simulator.rs (1)

121-121: LGTM!

asusctl/src/platform_cli.rs (8)

23-39: LGTM!


65-110: LGTM!


112-134: LGTM!


136-171: LGTM!


173-213: LGTM!


215-272: LGTM!


334-386: LGTM!


388-444: LGTM!

asusctl/src/main.rs (2)

4-19: LGTM!


48-48: LGTM!

Also applies to: 64-64

asusctl/src/slash_cli.rs (1)

2-2: LGTM!

Also applies to: 82-83, 139-160

asusctl/src/xgm_led_cli.rs (1)

11-19: LGTM!

asusctl/src/anime_cli.rs (3)

2-5: LGTM!

Also applies to: 9-37, 42-48, 56-79, 83-96, 113-132, 140-151


203-295: 🗄️ Data Integrity & Integration

Confirm behavior when find_iface_blocking returns more than one proxy.

for proxy in animes (line 203) applies image/GIF actions per device. For Gif/PixelGif, the media is decoded via from_gif/from_png inside this loop (lines 260-283), so with multiple proxies the same file gets redecoded once per device. More importantly, play_gif_animation (lines 308-328) blocks the calling thread on proxy, and when gif.loops == 0 it loops forever (None => continue). If more than one Anime proxy is ever returned, only the first device receives the animation and the command never advances to the rest of animes.

This may be a non-issue if each supported laptop model always exposes exactly one Anime D-Bus object (in which case the loop is effectively single-iteration), but rog_dbus::find_iface_blocking is shared, multi-device discovery infrastructure per the PR's "Blocking D-Bus discovery" layer. Confirm whether find_iface_blocking can return more than one AnimeProxyBlocking, and if so, hoist the media decode out of the loop and avoid blocking subsequent devices on an infinite GIF loop.

#!/bin/bash
# Description: Inspect find_iface_blocking's signature and behavior in rog-dbus.
fd -e rs . rog-dbus/src | xargs rg -n -B2 -A20 'fn find_iface_blocking'

Also applies to: 308-328


298-306: LGTM!

Also applies to: 330-338, 340-378

asusctl/src/fan_curve_cli.rs (4)

2-2: LGTM!

Also applies to: 46-48


69-72: 🩺 Stability & Availability

Verify that FanCurvesProxyBlocking::new() actually detects service unavailability.

This handler builds the proxy directly with FanCurvesProxyBlocking::new(conn) and maps any error to a "Fan curves unavailable" warning. The sibling handlers in platform_cli.rs and anime_cli.rs, and this file's neighbor scsi_cli.rs, all use rog_dbus::find_iface_blocking to discover the interface before calling it. If the derived blocking proxy new() does not itself validate that the destination interface exists on the bus (a common zbus proxy behavior, where errors only surface on the first method call), this map_err branch never triggers, and the intended "service availability guard" silently does not work. Confirm the proxy-construction semantics for FanCurvesProxyBlocking and align this handler with the find_iface_blocking pattern used elsewhere if construction alone does not validate availability.

#!/bin/bash
set -euo pipefail
fd -a 'lib.rs' rog-dbus
echo "---- find_iface_blocking definition ----"
rg -n -A 25 'pub fn find_iface_blocking' rog-dbus/src/lib.rs || true
echo "---- FanCurvesProxyBlocking definition/macro ----"
fd -a 'fan_curves' rog-dbus
rg -n -B3 -A 20 'FanCurvesProxyBlocking|dbus_proxy' rog-dbus/src/zbus_fan_curves.rs 2>/dev/null || true

83-86: LGTM!


88-115: LGTM!

asusctl/src/scsi_cli.rs (1)

34-41: LGTM!

Comment thread asusctl/src/anime_cli.rs
Comment thread asusctl/src/anime_cli.rs
Comment thread asusctl/src/main.rs
Comment thread asusctl/src/main.rs Outdated
Comment thread asusctl/src/platform_cli.rs
Comment thread asusctl/src/platform_cli.rs Outdated
Comment thread asusctl/src/platform_cli.rs Outdated
Comment thread asusctl/src/scsi_cli.rs Outdated
Comment thread asusd/src/daemon.rs Outdated
Comment on lines +25 to +33
log::info!("App and daemon versions:");
log::info!(" rog-gui v{}", VERSION);
log::info!(" asusd v{}", asusd::VERSION);
log::info!("\nComponent crate versions:");
log::info!(" rog-anime v{}", rog_anime::VERSION);
log::info!(" rog-aura v{}", rog_aura::VERSION);
log::info!(" rog-dbus v{}", rog_dbus::VERSION);
log::info!(" rog-profiles v{}", rog_profiles::VERSION);
log::info!(" rog-platform v{}", rog_platform::VERSION);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep --version visible with the default log filter.

main sets RUST_LOG to warn,... when it is unset. That filter suppresses every log::info! call here. As a result, rog-control-center --version produces no version output by default.

Keep this command output on stdout, or initialize the version path with an info log filter.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rog-control-center/src/lib.rs` around lines 25 - 33, Ensure the --version
path in main remains visible when RUST_LOG is unset by emitting the version
information directly to stdout or initializing that path with an info-level
filter. Update the version-reporting block containing the rog-gui, asusd, and
component crate version messages while preserving the existing output content.

@coderabbitai coderabbitai Bot added the rog-aura Keyboard / Aura RGB label Aug 4, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
rog-control-center/src/zbus_proxies.rs (1)

71-90: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Add or remove the GPU D-Bus proxy.

asusd does not declare or register xyz.ljones.Gpu; only this proxy defines the interface. Add the interface at /xyz/ljones/Gpu with the three String properties, or remove the proxy. Any call to it currently fails at runtime.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rog-control-center/src/zbus_proxies.rs` around lines 71 - 90, The GpuStatus
proxy references an unregistered asusd interface, so either register
xyz.ljones.Gpu at /xyz/ljones/Gpu with power_status, vendor, and mode String
properties in the asusd D-Bus implementation, or remove GpuStatus and its
callers from zbus_proxies.rs; ensure no runtime path still invokes an
unavailable interface.
asusctl/src/anime_cli.rs (1)

229-282: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Validate media brightness before any proxy write.

If a command combines a global setting or --clear with a media action, Lines 204-227 can change a device before Lines 232, 246, 258, or 273 reject bright. The error exits the loop and leaves later devices unchanged. Validate all media brightness values before find_iface_blocking and before for proxy in animes.

Proposed fix
     if let Some(action) = cmd.command.as_ref() {
         match action {
             AnimeActions::Image(image) if image.path.is_empty() => {
                 warn!("Missing arg or command; run 'asusctl anime image --help' for usage");
                 return Ok(());
             }
             AnimeActions::PixelImage(image) if image.path.is_empty() => {
                 warn!("Missing arg or command; run 'asusctl anime pixel-image --help' for usage");
                 return Ok(());
             }
             AnimeActions::Gif(gif) if gif.path.is_empty() => {
                 warn!("Missing arg or command; run 'asusctl anime gif --help' for usage");
                 return Ok(());
             }
             AnimeActions::PixelGif(gif) if gif.path.is_empty() => {
                 warn!("Missing arg or command; run 'asusctl anime pixel-gif --help' for usage");
                 return Ok(());
             }
             AnimeActions::SetBuiltins(builtins) if builtins.set.is_none() => {
                 warn!("Missing arg; run 'asusctl anime set-builtins --help' for usage");
                 return Ok(());
             }
+            AnimeActions::Image(image) => verify_brightness(image.bright)?,
+            AnimeActions::PixelImage(image) => verify_brightness(image.bright)?,
+            AnimeActions::Gif(gif) => verify_brightness(gif.bright)?,
+            AnimeActions::PixelGif(gif) => verify_brightness(gif.bright)?,
             _ => {}
         }
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@asusctl/src/anime_cli.rs` around lines 229 - 282, Move brightness validation
for every media action out of the per-proxy match and perform it before
find_iface_blocking and the for proxy in animes loop. Ensure Image, PixelImage,
Gif, and PixelGif brightness values are validated whenever present, before any
global-setting or --clear operation can modify a device; remove the later
duplicate validations while preserving the existing media handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@asusctl/src/main.rs`:
- Around line 26-33: Update logger initialization around the env_logger::Builder
flow to use Env::default().default_filter_or(...) with Builder::from_env,
preserving an explicitly configured global RUST_LOG filter while retaining the
existing info/tracing/zbus default and stdout target. Remove the
filter_level(LevelFilter::Info) call that overrides parsed environment
directives.

---

Outside diff comments:
In `@asusctl/src/anime_cli.rs`:
- Around line 229-282: Move brightness validation for every media action out of
the per-proxy match and perform it before find_iface_blocking and the for proxy
in animes loop. Ensure Image, PixelImage, Gif, and PixelGif brightness values
are validated whenever present, before any global-setting or --clear operation
can modify a device; remove the later duplicate validations while preserving the
existing media handling.

In `@rog-control-center/src/zbus_proxies.rs`:
- Around line 71-90: The GpuStatus proxy references an unregistered asusd
interface, so either register xyz.ljones.Gpu at /xyz/ljones/Gpu with
power_status, vendor, and mode String properties in the asusd D-Bus
implementation, or remove GpuStatus and its callers from zbus_proxies.rs; ensure
no runtime path still invokes an unavailable interface.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a73cc0ba-a8e8-4311-ab70-be9804172bf4

📥 Commits

Reviewing files that changed from the base of the PR and between dbd9a0e and 3ac9561.

📒 Files selected for processing (9)
  • asusctl/src/anime_cli.rs
  • asusctl/src/main.rs
  • asusctl/src/platform_cli.rs
  • asusctl/src/scsi_cli.rs
  • asusctl/src/slash_cli.rs
  • asusctl/src/xgm_led_cli.rs
  • asusd/src/daemon.rs
  • rog-control-center/src/main.rs
  • rog-control-center/src/zbus_proxies.rs
📜 Review details
🔇 Additional comments (11)
asusd/src/daemon.rs (1)

23-24: LGTM!

Also applies to: 32-42, 59-59

rog-control-center/src/zbus_proxies.rs (2)

1-2: LGTM!


91-91: LGTM!

rog-control-center/src/main.rs (2)

30-30: LGTM!


86-91: LGTM!

asusctl/src/anime_cli.rs (1)

35-36: LGTM!

Also applies to: 193-201, 284-292

asusctl/src/scsi_cli.rs (1)

34-105: LGTM!

asusctl/src/platform_cli.rs (1)

41-48: LGTM!

Also applies to: 286-307, 464-468, 516-555

asusctl/src/slash_cli.rs (1)

70-90: LGTM!

Also applies to: 126-151

asusctl/src/xgm_led_cli.rs (1)

4-22: LGTM!

asusctl/src/main.rs (1)

83-83: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Dispatch scsi --list before the asusd preflight.

handle_scsi returns static AuraMode::list() output before its D-Bus lookup. However, Line 83 runs only after the platform version, property, and interface checks. If asusd is unavailable, the version check returns first and asusctl scsi --list never reaches the daemon-free handler. This breaks the stated daemon-free scsi --list behavior.

Proposed fix
     let parsed: CliStart = argh::from_env();

+    if let CliCommand::Scsi(cmd) = &parsed.command {
+        if cmd.list {
+            if let Err(err) = scsi_cli::handle_scsi(cmd) {
+                error!("{err}");
+            }
+            return;
+        }
+    }
+
     let conn = match Connection::system() {
			> Likely an incorrect or invalid review comment.

Comment thread asusctl/src/main.rs
Comment on lines 26 to +33
if std::env::var_os("RUST_LOG").is_none() {
std::env::set_var("RUST_LOG", "warn,tracing=error,zbus=error");
std::env::set_var("RUST_LOG", "info,tracing=error,zbus=error");
}
let mut logger = env_logger::Builder::new();
logger
.parse_default_env()
.filter_level(LevelFilter::Info)
.target(env_logger::Target::Stderr)
.target(env_logger::Target::Stdout)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

lockfile="$(fd -t f '^Cargo\.lock$' . | head -n 1)"
test -n "$lockfile"

version="$(
  awk '
    $0 == "name = \"env_logger\"" { found = 1; next }
    found && /^version = / { gsub(/"/, "", $3); print $3; exit }
  ' "$lockfile"
)"
test -n "$version"

curl -fsSL "https://docs.rs/crate/env_logger/${version}/source/src/logger.rs" |
  rg -n -C 8 'parse_env|parse_default_env|filter_level|default_filter_or'

Repository: OpenGamingCollective/asusctl

Length of output: 166


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- candidate files ---'
fd -t f '^(main\.rs|Cargo\.lock|Cargo\.toml)$' . | sort

printf '%s\n' '--- logging code ---'
main="$(fd -t f '^main\.rs$' . | awk '$0=="asusctl/src/main.rs"{print; exit}')"
test -n "$main"
cat -n "$main" | sed -n '1,80p'

printf '%s\n' '--- env_logger dependency declarations ---'
rg -n -C 3 'env_logger|RUST_LOG|parse_default_env|filter_level|default_filter_or' \
  --glob 'Cargo.toml' --glob 'Cargo.lock' --glob '*.rs' .

Repository: OpenGamingCollective/asusctl

Length of output: 665


🌐 Web query:

env_logger Builder parse_default_env filter_level precedence filter_level source

💡 Result:

In the env_logger crate, explicit configuration methods on the Builder (such as filter_level) and environment-based configuration methods (such as parse_default_env or parse_env) can be combined. When both are used, the environment configuration overrides or appends to the existing configuration set by the builder [1][2]. Specifically, the parse_default_env and parse_env methods apply directives from the specified environment variables to the builder's internal configuration [1][2]. If you call filter_level to set an initial baseline (e.g., LevelFilter::Off) and then call parse_default_env, the directives found in the environment variable (typically RUST_LOG) will be applied, effectively overriding or refining the previously set filter [1][2]. Key points regarding precedence and behavior: - Builder methods like filter_level and filter modify the builder's state before the logger is initialized [1][2]. - Environment parsing methods like parse_default_env read from the environment and add/update those directives in the builder [1][2]. - Documentation examples explicitly show this pattern: initializing the builder, setting a baseline filter level (e.g., Off), and then calling parse_default_env to allow the environment variables to dictate the final logging behavior [1][2]. The source code for Builder::parse_default_env confirms it is a convenience wrapper that calls parse_env using the default environment settings [3]. Because these methods are applied sequentially on the mutable Builder, the order of operations dictates the final state: configuration applied last generally has the final say [1][2].

Citations:


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- asusctl logging code ---'
cat -n asusctl/src/main.rs | sed -n '1,75p'

printf '%s\n' '--- env_logger dependency ---'
rg -n -C 4 'env_logger' Cargo.toml asusctl/Cargo.toml

printf '%s\n' '--- lockfiles ---'
fd -t f '^Cargo\.lock$' . | sort || true

Repository: OpenGamingCollective/asusctl

Length of output: 4031


🌐 Web query:

env_logger 0.11.8 source Builder filter_level parse_default_env FilterBuilder directives precedence

💡 Result:

In env_logger 0.11.8, the Builder is used to construct a logger configuration [1][2]. Regarding your specific queries: Builder and filter_level: The filter_level(level) method adds a global directive to the logger, setting a minimum log level for all modules [1][3]. This global directive is applied to all log targets unless more specific module-level filters are provided [2][3]. parse_default_env and Precedence: The parse_default_env method is a convenience function that invokes parse_env(Env::default) [4][5]. It reads the RUST_LOG environment variable (or the default variable configured) and applies those directives to the builder [2][4]. Crucially, env_logger does not provide a built-in mechanism where "programmatic" configuration (such as calling.filter or.filter_level on the builder) automatically takes precedence over or is merged with environment variable configuration in a "soft" way [1][6]. When you call parse_env or parse_default_env, the directives found in the environment variable are added to the existing configuration [4]. If there is a conflict (e.g., you set a module to Off programmatically, but RUST_LOG enables it), the behavior depends on the order of operations [7][6]. Typically, later directives in the combined list take precedence over earlier ones [2]. Because parse_env appends to the builder's internal state, environment variables effectively act as additional filters that can override or augment your manual settings depending on the syntax used in the environment string [2][6]. Directive Precedence: env_logger uses the filter syntax defined by the env_filter crate [2][3]. When multiple directives are present, they are evaluated based on their specificity: 1. Specificity: A directive for a specific module (e.g., my_crate::module=info) takes precedence over a global directive (e.g., info) [2]. 2. Order: If multiple directives apply to the same module or if there are multiple global directives, the last one specified generally governs the behavior [2]. To ensure your programmatic filters (like setting a dependency to 'off') persist regardless of the user's RUST_LOG input, you should configure your builder such that the environment variables are parsed first or carefully structure the directive string [7][6]. Note that there is no native way to make programmatic "hard" filters that strictly override RUST_LOG without explicit logic in your code to manage that precedence [6].

Citations:


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT

curl -fsSL \
  'https://docs.rs/crate/env_logger/0.11.11/source/src/logger.rs' \
  -o "$tmp/logger.rs"

printf '%s\n' '--- env_logger Builder methods ---'
rg -n -C 12 \
  'pub fn (parse_default_env|parse_env|filter_level)|filter_level\(' \
  "$tmp/logger.rs"

printf '%s\n' '--- filter implementation references ---'
rg -n -C 8 'filter_level|add_filter|filter::Builder|parse_env' "$tmp/logger.rs"

Repository: OpenGamingCollective/asusctl

Length of output: 50386


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT

curl -fsSL \
  'https://docs.rs/crate/env_filter/0.1.4/source/src/builder.rs' \
  -o "$tmp/builder.rs"

printf '%s\n' '--- env_filter directive insertion and precedence ---'
rg -n -C 12 \
  'filter_level|add_filter|parse|directives|last|override' \
  "$tmp/builder.rs"

Repository: OpenGamingCollective/asusctl

Length of output: 1471


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT

curl -fsSL \
  'https://crates.io/api/v1/crates/env_logger/0.11.11/download' \
  -o "$tmp/env_logger.crate"
tar -xzf "$tmp/env_logger.crate" -C "$tmp"

printf '%s\n' '--- env_logger source ---'
rg -n -A14 -B8 \
  'pub fn parse_default_env|pub fn parse_env|pub fn filter_level' \
  "$tmp"/env_logger-0.11.11/src/logger.rs

printf '%s\n' '--- env_logger dependency versions ---'
rg -n 'env_filter|version' "$tmp"/env_logger-0.11.11/Cargo.toml | head -n 20

printf '%s\n' '--- env_filter source ---'
curl -fsSL \
  'https://crates.io/api/v1/crates/env_filter/0.1.4/download' \
  -o "$tmp/env_filter.crate"
tar -xzf "$tmp/env_filter.crate" -C "$tmp"

rg -n -A18 -B8 \
  'pub fn filter_level|fn filter_level|pub fn parse|fn parse|directives' \
  "$tmp"/env_filter-0.1.4/src

Repository: OpenGamingCollective/asusctl

Length of output: 217


🌐 Web query:

site:docs.rs/env_filter/0.1.4 env_filter Builder filter_level source default level parse directives

💡 Result:

For env_filter 0.1.4:

  • Builder::filter_level(level) adds a global directive (module = None). (docs.rs)
  • Builder::filter(module, level) applies the level to a specific module, or globally when module is None. (docs.rs)
  • parse("info,crate1::mod1=warn") parses comma-separated directives. Bare levels such as info, warn, error, and off set the global level; module directives use module=level. (docs.rs)
  • parse prints warnings and ignores invalid directives; try_parse returns ParseError. (docs.rs)
  • If no directives exist when build() runs, the default global level is Error. (docs.rs)
  • Filter::filter() returns the maximum configured level, or LevelFilter::Off if none are configured. (docs.rs)

Citations:


🌐 Web query:

site:docs.rs/env_logger/0.11.11 "filter_level" "parse_default_env" "override"

💡 Result:

env_logger 0.11.11 documents that:

let mut builder = env_logger::Builder::new();

builder.filter_level(log::LevelFilter::Off);
builder.parse_default_env();
builder.init();

parse_default_env() reads the default environment variables—primarily RUST_LOG—and allows them to override previously configured filters. It is equivalent to parse_env(Env::default()). [1][2]

The custom-variable form is:

builder.filter_level(LevelFilter::Off);
builder.parse_env("MY_LOG");

[1] (docs.rs)
[2] (docs.rs)

Citations:


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

tmp="$(mktemp)"
trap 'rm -f "$tmp"' EXIT

curl -fsSL \
  'https://docs.rs/crate/env_filter/0.1.4/source/src/filter.rs' |
  python3 -c '
import html, sys
from html.parser import HTMLParser

class Text(HTMLParser):
    def __init__(self):
        super().__init__()
        self.out = []
    def handle_data(self, data):
        self.out.append(data)
    def get(self):
        return html.unescape("".join(self.out))

p = Text()
p.feed(sys.stdin.read())
print(p.get())
' > "$tmp"

rg -n -A20 -B12 \
  'struct Filter|fn enabled|directives|filter_level|sort|match|LevelFilter' \
  "$tmp"

Repository: OpenGamingCollective/asusctl

Length of output: 23719


Preserve an explicit global RUST_LOG filter.

filter_level(LevelFilter::Info) runs after parse_default_env() and replaces its global directive. Thus, RUST_LOG=error and RUST_LOG=debug both use global info. Use Env::default().default_filter_or(...) with Builder::from_env instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@asusctl/src/main.rs` around lines 26 - 33, Update logger initialization
around the env_logger::Builder flow to use Env::default().default_filter_or(...)
with Builder::from_env, preserving an explicitly configured global RUST_LOG
filter while retaining the existing info/tracing/zbus default and stdout target.
Remove the filter_level(LevelFilter::Info) call that overrides parsed
environment directives.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

asusctl CLI Tool asusd System Daemon / D-Bus fix Fix a bug or an issue rog-anime AniMe Matrix Display rog-aura Keyboard / Aura RGB rog-control-center ROG Control Center GUI rog-platform GPU Switching / Armoury / WMI rog-scsi Drive / SCSI LED rog-slash Slash LED Bar

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant